/*************************************************************************
 * All portions of code are copyright by their respective author/s.
 * Copyright (C) 2007      Bryan Christ <bryan.christ@hp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------*/

#include <stdlib.h>
#include <string.h>

#include "shmq.h"
#include "pseudo.h"

SHMQ*
shmq_init(const char *queue_name)
{
	static GSList			*queue_list = NULL;
	static uint8_t			queue_list_length=0;
	GSList					*node;
	SHMQ						*shmq;

	/* set a default queue */
	if(queue_name == NULL) queue_name="default";

	/* create a new shmq if the master list of queues is empty */
	if(queue_list_length == 0)
	{
		queue_list=NULL;

        shmq = (SHMQ*)calloc(1,sizeof(SHMQ));
		queue_list=g_slist_append(queue_list,(gpointer)shmq);

		memset(shmq->queue_name,0,sizeof(shmq->queue_name));
		strncpy(shmq->queue_name,queue_name,sizeof(shmq->queue_name)-1);
		queue_list_length++;

		return shmq;
	}

	/* look for an already existing queue */	
	node=queue_list;
	while(node!=NULL)
	{
		shmq=(SHMQ*)node->data;
		if(strcmp(queue_name,shmq->queue_name)==0) break;
		node=node->next;
	}

	/* return an existing queue */
	if(node!=NULL)
	{
		return shmq;
	}

	/* create and add a new queue */
	shmq=(SHMQ*)g_malloc0(sizeof(SHMQ));
	queue_list=g_slist_prepend(queue_list,(gpointer)shmq);
	memset(shmq->queue_name,0,sizeof(shmq->queue_name));
	strncpy(shmq->queue_name,queue_name,sizeof(shmq->queue_name)-1);
	queue_list_length++;

	return shmq;
}

int16_t shmq_msg_put(const gchar *queue,gpointer anything)
{
	SHMQ	*shmq;

	if(queue == NULL) return SHMQ_QUEUE_INVALID;
	if(anything == NULL) return SHMQ_MSG_INVALID;
	shmq=shmq_get(queue);
	if(shmq == NULL) return SHMQ_QUEUE_INVALID;

	if(shmq->msg_count > INT16_MAX)
	{
		return SHMQ_QUEUE_FULL;
	}
	shmq->queue=g_slist_append(shmq->queue,anything);
	shmq->msg_count++;

	return SHMQ_OK;
}

void* shmq_msg_get(const char *queue)
{
	SHMQ			*shmq;
	void        *anything=NULL;
	GSList		*node;

	if(queue == NULL) return NULL;
	shmq=shmq_get(queue);

	if(shmq->msg_count > 0)
	{
		node=shmq->queue;
		anything=node->data;
		shmq->msg_count--;
		if(shmq->msg_count > 0)
			shmq->queue=g_slist_delete_link(shmq->queue,node);
		else
		{
			g_slist_free(shmq->queue);
			shmq->queue=NULL;
		}
	}

	return anything;
}

uint16_t shmq_size(const char *queue)
{
	SHMQ			*shmq;

	if(queue == NULL) return 0;
	shmq=shmq_get(queue);

	return shmq->msg_count;
}
